using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace System.Windows.Forms
{
    /// <summary>
    /// Summary description for PopupForm
    /// </summary>
    public class PopupForm : System.Windows.Forms.Form
    {
        private System.ComponentModel.IContainer components = null;
        private Form mdiParent;
        private Control owner;
        private Form parentForm;

        /// <summary>
        /// Default constructor
        /// </summary>
        public PopupForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Raised after the popup window closes
        /// </summary>
        public event EventHandler Popped;

        /// <summary>
        /// Raised when the popup window opens
        /// </summary>
        public event EventHandler Popup;

        /// <summary>
        /// Parent property override
        /// </summary>
        public System.Windows.Forms.Control OwnerControl
        {
            get { return owner; }
            set
            {
                if (owner != null)
                {
                    if (!object.ReferenceEquals(owner.Parent, parentForm))
                    {
                        owner.Parent.MouseDown -= new System.Windows.Forms.MouseEventHandler(ParentMouseEvent);
                    }

                    parentForm.LostFocus -= new System.EventHandler(ParentEvent);
                    parentForm.MouseDown -= new System.Windows.Forms.MouseEventHandler(ParentMouseEvent);
                    parentForm.Move -= new System.EventHandler(ParentEvent);

                    if (mdiParent != null)
                    {
                        mdiParent.LostFocus -= new System.EventHandler(ParentEvent);
                        mdiParent.MouseDown -= new System.Windows.Forms.MouseEventHandler(ParentMouseEvent);
                        mdiParent.Move -= new System.EventHandler(ParentEvent);
                    }

                    parentForm = null;
                    mdiParent = null;
                }

                owner = value;
                if (value != null)
                {
                    parentForm = owner.FindForm();

                    if (Form.ActiveForm != null && Form.ActiveForm.IsMdiContainer)
                    {
                        mdiParent = Form.ActiveForm;

                        mdiParent.LostFocus += new System.EventHandler(ParentEvent);
                        mdiParent.MouseDown += new System.Windows.Forms.MouseEventHandler(ParentMouseEvent);
                        mdiParent.Move += new System.EventHandler(ParentEvent);
                    }

                    parentForm.LostFocus += new System.EventHandler(ParentEvent);
                    parentForm.MouseDown += new System.Windows.Forms.MouseEventHandler(ParentMouseEvent);
                    parentForm.Move += new System.EventHandler(ParentEvent);

                    if (!object.ReferenceEquals(owner.Parent, parentForm))
                    {
                        owner.Parent.MouseDown += new System.Windows.Forms.MouseEventHandler(ParentMouseEvent);
                    }
                }
            }
        }

        /// <summary>
        /// Overriden CreateParams to make topmost
        /// </summary>
        protected override CreateParams CreateParams
        {
            get
            {
                // Extend the CreateParams property
                CreateParams cp = base.CreateParams;

                // Update the window Style.
                cp.ExStyle |= 0x00000008; //WS_EX_TOPMOST

                return cp;
            }
        }

        /// <summary>
        /// Closes the popup window
        /// </summary>
        public virtual void Pop()
        {
            this.Hide();
            if (Popped != null)
                Popped(this, new EventArgs());
        }

        /// <summary>
        /// Shows popup window at owner's bottom-left point
        /// </summary>
        /// <param name="owner">Control that owns the popup</param>
        public void Show(Control owner)
        {
            Point pt = owner.Parent.PointToScreen(new Point(owner.Right-this.Width, owner.Bottom));
            if ((pt.Y+this.Height) > SystemInformation.PrimaryMonitorSize.Height)
                pt = owner.Parent.PointToScreen(new Point(owner.Right-this.Width, owner.Top-this.Height));
            Show(owner, pt);
        }

        [DllImport("User32.dll", CharSet=CharSet.Auto)]
        internal static extern int ShowWindow(IntPtr hWnd, short cmdShow);

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                Parent = null;

                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// Override OnLostFocus to close form
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLostFocus(System.EventArgs e)
        {
            base.OnLostFocus(e);
            Pop();
        }

        /// <summary>
        /// Raises the Popup event
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnPopup(System.EventArgs e)
        {
            if (Popup != null)
                Popup(this, e);
        }

        /// <summary>
        /// Override Show to hide
        /// </summary>
        protected new void Show()
        {
            base.Show();
        }

        /// <summary>
        /// Overriden WndProc to disallow mouse activation of window
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x0021) //WM_MOUSEACTIVATE
            {
                // Do not allow then mouse down to activate the window, but eat
                // the message as we still want the mouse down for processing
                m.Result = (IntPtr)3; //MA_NOACTIVATE
                return;
            }

            base.WndProc(ref m);
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            //
            // PopupForm
            //
            this.AutoScaleMode = AutoScaleMode.None;
            this.ClientSize = new System.Drawing.Size(100, 100);
            this.ControlBox = false;
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "PopupForm";
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
            this.Text = "PopupForm";
        }

        private void ParentEvent(object sender, System.EventArgs e)
        {
            Pop();
        }

        private void ParentMouseEvent(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            Pop();
        }

        /// <summary>
        /// Shows popup window
        /// </summary>
        /// <param name="owner">Control that owns the popup</param>
        /// <param name="location">Top-left location of popup</param>
        private void Show(Control owner, Point location)
        {
            this.OwnerControl = owner;
            this.Location = location;
            int w = this.Width;		// Get pre-show width to fix WmCreate bug
            ShowWindow(this.Handle, 4);
            this.Width = w;			// Set post show width to right size
            OnPopup(new EventArgs());
        }
    }
}